home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d12 / cc02.arc / CREF.C < prev    next >
Text File  |  1986-03-14  |  7KB  |  345 lines

  1. /*  cref.c        cross-reference utility for `C' compilers.  */
  2.  
  3. #include <stdio.h>
  4. #include <local.h>
  5.  
  6. /******************************
  7. *  C cross reference utility  *
  8. ******************************/
  9.  
  10. /*  (c) 1982 by the Toolsmith  */
  11.  
  12. typedef  short    boolean;
  13.  
  14. #include "lexcmp.c"
  15. #include "diagn.c"
  16. #include "esc.c"
  17. #include "linked.c"
  18. #include "string.c"
  19.  
  20. struct instance {
  21.     struct     instance *link;
  22.     int        line;
  23. };
  24.  
  25. union ptr {
  26.     struct node *files;
  27.     struct instance *lines;
  28. };
  29.  
  30. struct node {
  31.     struct node *right, *left;
  32.     union     ptr    p;
  33.     char     *name;
  34. };
  35.  
  36. struct node *symbol_root = NULL;
  37. struct node *file_root = NULL;
  38.  
  39. #define ID 'a'          /* identifier */
  40. #define INTEGER '0'     /* integer */
  41.  
  42. /*********************************
  43. *  Symbol Table handling routines  *
  44. ***********************************/
  45.  
  46. /*  lookup - install name at or below root  */
  47.  
  48. struct node **lookup(root, name)
  49. register struct node **root;
  50. register    char     *name;
  51. {
  52.     register    int    cond;
  53.  
  54.     if(*root != NULL) {
  55.                 if((cond = lexcmp(name, (*root)->name, 0)) < 0)
  56.             root = lookup(&(*root)->left, name);
  57.         else if(cond > 0)
  58.             root = lookup(&(*root)->right, name);
  59.  }
  60.  
  61.     return root;
  62. }
  63.  
  64. /* add - insert entry for "name" in tree at "root" */
  65.  
  66. add(root, name)
  67. struct node **root;
  68. char     *name;
  69. {
  70.     extern char *calloc();
  71.     register struct node *r;
  72.  
  73.     r = (struct node *) calloc(1, sizeof(struct node));
  74.     r->left = r->p.lines = NULL;
  75.     r->name = name;
  76.     *root = r;
  77. }
  78.  
  79. /* tree_walk - walk a binary tree, doing ftn to each node */
  80.  
  81. tree_walk(root, ftn)
  82. register struct node *root;
  83. register (*ftn)();
  84. {
  85.        if(root != NULL) {
  86.         tree_walk(root->left, ftn);
  87.         (*ftn)(root);
  88.         tree_walk(root->right,ftn);
  89.     }
  90. }
  91.  
  92. /* use - log an occurence of "name" in "file" at "line" */
  93.  
  94. use(name, file, line)
  95. char *name, *file;
  96. int  line;
  97. {
  98.     register struct instance **it;
  99.     register struct node **ft, **nt;
  100.  
  101.     if(*(nt = lookup(&symbol_root, name)) == NULL)
  102.         add(nt, newcpy(name));
  103.  
  104.     if(*(nt = lookup(&((*nt)->p.files), file)) == NULL) {
  105.         if(*(ft = lookup(&file_root, file)) == NULL)
  106.             add(ft, newcpy(file));
  107.         add(nt, (*ft)->name);
  108.     }
  109.     it = &((*nt)->p.lines);
  110.     if(*it == NULL || (*it)->line != line) {
  111.         *it = (struct instance *) insert(sizeof(struct instance), nt);
  112.         (*it)->line = line;
  113.     }
  114. }
  115.  
  116. /* get_name - extract file name from line */
  117.  
  118. unsigned get_name(line, file)
  119. register char *line;
  120. char *file;
  121. {
  122.     register unsigned n;
  123.     register char *delim;
  124.  
  125.     while(*line == ' ' || *line == '\t')
  126.         ++line;
  127.     if(*line == '\n')
  128.         n = lenstr(file);
  129.     else {
  130.         if(*line == '"') {
  131.             delim = "\"\n";
  132.             ++line;
  133.         } else if(*line == '<') {
  134.             delim = ">\n";
  135.             ++line;
  136.         } else
  137.             delim = " \t\n";
  138.         n = cpybuf(file, line, instr(line, delim));
  139.         file[n] = '\0';
  140.     }
  141.  
  142.     return n;
  143. }
  144.  
  145. unsigned line_count = 0;
  146.  
  147. /* new_line - return pointer to next line */
  148.  
  149. char *new_line()
  150. {
  151.     extern unsigned gets();
  152.     static char line[MAXLINE + 1];
  153.  
  154.     ++line_count;
  155.     line[gets(line, MAXLINE)] = '\0';
  156.  
  157.     return line;
  158. }
  159.  
  160. /* white_space - tests for blanks, tabs and comments */
  161.  
  162. boolean white_space(s)
  163. register char **s;
  164. {
  165.     if (**s == ' ' || **s == '\t')
  166.         return YES;
  167.     if (**s == '/' && *(*s+1) == '*') { /* comment */
  168.         while (*++*s != '/')
  169.             while (*++*s != '*')
  170.                 if (**s == '\0')
  171.                     if (*(*s = new_line()))
  172.                         --*s;
  173.                     else {
  174.                         diagnostic(NO, "unexpected EOF", NULL);
  175.                         return NO;
  176.                     }
  177.         return YES;
  178.     }
  179.     return NO;
  180. }
  181.  
  182. /* get_token - strip leading token from s */
  183.  
  184. char get_token(s, t)
  185. register char **s, *t;
  186. {
  187.     register char class;
  188.  
  189.     while (white_space(s))
  190.         ++*s;
  191.     if (isalpha(**s) || **s == '_') {  /* identifier */
  192.         class = ID;
  193.         do
  194.             *(t++) = *((*s)++);
  195.         while (isdigit(**s) || isalpha(**s) || **s == '_');
  196.     } else if(**s == '"' || **s == '\'') {  /* string or literal */
  197.         class = **s;
  198.         do {
  199.             esc(s);
  200.             ++*s;
  201.             if (**s == '\0')
  202.                 if (*(*s = new_line()) == '\0')
  203.                     goto out;
  204.         } while (**s != class);
  205.         ++*s;
  206.     } else if (isdigit(**s)) {
  207.         do {
  208.             class = *++*s;
  209.             class = tolower(class);
  210.         } while (ishex(class) || class == 'x' || class == 'l' || class == '.');
  211.         class = INTEGER;
  212.     } else {
  213.         class = **s;
  214.         ++*s;
  215.     }
  216. out:
  217.     *t = '\0';
  218.     return class;
  219. }
  220.  
  221. /*  keyword - is "s" a reserved word in C  */
  222. boolean keyword(s)
  223. register char *s;
  224. {
  225.     register char **k;
  226.     register int c;
  227.     static char *reserved[] = {"auto", "break", "case", "char", "continue",
  228.         "default", "do", "double", "else", "entry", "extern", "float", "for", "goto",
  229.         "if", "int", "long", "register", "return", "short", "sizeof", "static",
  230.         "struct", "switch", "typedef", "union", "unsigned", "while",NULL};
  231.  
  232.     for (k = reserved; *k = NULL; ++k)  /* reserved must be sorted */
  233.         if ((c = lexcmp(s, *k)) <= 0)
  234.             break;
  235.  
  236.     return(c == 0);    /* equality */
  237. }
  238.  
  239. /*  xref - cross reference */
  240. xref(file)
  241. register char *file;
  242. {
  243.     extern unsigned btoi();
  244.     register char c;
  245.     char *s, token[MAXLINE+1];
  246.  
  247.     line_count = 0;
  248.  
  249.     while (*(s = new_line())) {
  250.         if ((c = get_token(&s, token)) != '#')
  251.             while (c != '\n') {
  252.                 if (c == ID && !keyword(token))
  253.                     use(token, file, line_count);
  254.                 c = get_token(&s, token);
  255.             }
  256.         else if (get_token(&s, token) == ID) {
  257.             if (cmpstr(token, "include")) {
  258.                 get_name(s, token);
  259.                 use(token, file, line_count);
  260.             } else if (cmpstr(token, "define")) {
  261.                 get_token(&s, token);
  262.                 use(token, file, line_count);
  263.             } else if (cmpstr(token, "ifdef") || cmpstr(token, "ifndef")) {
  264.                 get_token(&s, token);
  265.                 use(token, file, line_count);
  266.             } else if (cmpstr(token, "line")) {
  267.                 if (get_token(&s, token) == INTEGER)
  268.                     btoi(token, MAXLINE, &line_count, 10);
  269.                 else
  270.                     diagnostic(NO, "#line ", token, NULL);
  271.             } else
  272.                 diagnostic(NO, "#", token, *s, NULL);
  273.         }
  274.     }
  275. }
  276.  
  277. /* puts - output s string to STDOUT */
  278. /*
  279. * unsigned puts(s)
  280. * char *s;
  281. * {
  282. *      return putlin(s, lenstr(s));
  283. * }
  284. */
  285.  
  286. /*  list_file - print lines within a file  */
  287.  
  288. list_file(ft)
  289. register struct node *ft;
  290. {
  291.     extern unsigned itob();
  292.     register unsigned b;
  293.     register struct instance *it;
  294.     char buf[5];
  295.  
  296.     b = puts("    ");
  297.     /*  print line numbers    */
  298.     for (it = reverse(ft->p.lines); it != NULL; it = it->link) {
  299.         if (b == 0)
  300.             b = puts("       ");    /*  this and 2nd to last line must agree */
  301.         b += puts("   ");
  302.         buf[itob(buf, it->line, 0)] = '\0';
  303.         b += puts(buf);
  304.  
  305.         if (b > HARD_WIDTH - 10) {
  306.             puts("\n");
  307.             b = 0;
  308.         }
  309.     }
  310.     if (b > 6) /*  non-blank line  */
  311.         puts("\n");
  312. }
  313.  
  314. /* print_xref - dump cross reference to stdout */
  315.  
  316. print_xref(nt)
  317. struct node *nt;
  318. {
  319.     puts(nt->name);
  320.     puts("\n");
  321.     tree_walk(nt->p.files, &list_file);
  322. }
  323.  
  324.  
  325. boolean main(ac, av)
  326. register int ac;
  327. register char **av;
  328. {
  329.     extern FILE *fclose(), *fopen();
  330.     FILE *cur_file;
  331.  
  332.     if (ac <= 1)
  333.         xref("<stdin>");
  334.     else
  335.         while (--ac > 0)
  336.             if ((cur_file = fopen(*++av, "r")) == NULL)
  337.                 diagnostic(NO, "can't open ", *av, NULL);
  338.             else {
  339.                 xref(*av);
  340.                 fclose(cur_file);
  341.             }
  342.     tree_walk(symbol_root, &print_xref);
  343.     return YES;
  344. }
  345.